<?php
use Config\Base as Config;
use DB\FacebookService;
use Models\User;

/**
 * @author Evgeny Baranov <evgeny@baranov.eu>
 */

class App {

    /**
     * @var \Models\User
     */
    private static $current_user;

    /**
     * @var \Controllers\Base
     */
    private $controller;

    /**
     * @var string
     */
    private $action;

    /**
     * @var array
     */
//    private static $param;

    /**
     * @var Document
     */
    private static $document;

    private static $lang;

    function __construct() {
        spl_autoload_register(array('App', 'autoload'), true);
        set_exception_handler(array('App', 'exceptionHandler'));

        // Init INI config
        $ini = preg_replace('/^www./', '', $_SERVER['HTTP_HOST']) . '.ini';
        Config::load(CFG_DIR . DS . $ini);

        // Session start
        \DB\SessionService::bind('ozo');

        $this->route();
    }

    /**
     * @throws Exception
     */
    private function route() {
        // TODO: move to Language dispatcher

        $l = Path::getInstance()->current();
        if ($l && in_array($l, Config::instance()->lang->list)) {
            self::setLang($l);
            Path::getInstance()->next();
        } else {
            if (!empty($_GET['lang']) && in_array($_GET['lang'], Config::instance()->lang->list)) {
                self::setLang($_GET['lang']);
            }
        }

        // TODO: move to User dispatcher
        if (!empty($_SESSION['user_id'])) {
            $us = new \DB\UserService();
            $user = $us->getUser($_SESSION['user_id']);
            self::setCurrentUser($user);
        }

        // TODO: move to menu router/dispatcher
        \Views\Widgets\Menu::route($this);

        // TODO: move to Document dispatcher, add selection of doc type (XML, HTML, JSON)
        self::$document = new Document();

        self::$document
            ->addMetaHttp("Content-Type", "text/html; charset=" . Config::instance()->lang->charset)
            ->addMetaOG('app_id', Config::instance()->facebook->APP_ID, 'fb')
            ->addMetaOG('page_id', Config::instance()->facebook->PAGE_ID, 'fb')
            ->addMetaOG('image', 'http://sphotos-a.ak.fbcdn.net/hphotos-ak-snc7/397619_460194027372552_1623927432_n.png')
            ->setTitle(Config::instance()->title);


        self::$document->addCSSLink(array(
            '//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css',
            '/css/main.css'
        ))->addScript(array(
                '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js',
                '//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js'
            ))->addIcon('/img/ozoteniss-ball-32x32.png', 'image/png');

        // TODO: move to Controller dispatcher
        // If controller not set from menu, try find in path
        if (!$this->controller) {
            if (Path::getInstance()->valid() && Path::getInstance()->current()) {
                $c = Path::getInstance()->current();
                if ($c == 'admin') {
                    Path::getInstance()->next();
                    $c .= Path::getInstance()->current();
                }
                $this->setController($c);
                Path::getInstance()->next();
            }
        }

        // if still empty set default controller
        if (!$this->controller) {
            $this->setController('Index');
        }

        // set action
        if (!$this->action) {
            if (Path::getInstance()->valid()) {
                $a = Path::getInstance()->current();
                if ($this->controller->haveAction($a)) {
                    $this->setAction($a);
                    Path::getInstance()->next();
                } else {
                    $this->setAction($this->controller->getDefaultAction());
                }
            }
        } else {
            if (Path::getInstance()->valid()) {
                $a = Path::getInstance()->current();
                if ($this->controller->haveAction($a)) {
                    $this->setAction($a);
                    Path::getInstance()->next();
                }
            }
        }

        $this->output();
    }

    /**
     *
     * @param string $class_name
     * @throws Exception
     */
    public static function autoload($class_name) {
        $root = array_shift(explode(NS, $class_name));
        $file_name = DS . str_replace(NS, DS, $class_name) . '.php';

        switch ($root) {
            case 'Facebook':
                $file_name = FB_DIR . strtolower($file_name);
                break;
            default:
                $file_name = APP_DIR . $file_name;
        }
        if (is_readable($file_name)) {
            require_once $file_name;
        } else {
            throw new Exception("Class '$class_name' not found!");
        }
    }

    /**
     *
     * @param \Exception $e
     */
    public static function exceptionHandler(\Exception $e) {
        error_log($e->getMessage());
        echo '<h3>' . $e->getMessage() . '</h3>';
        echo '<pre><small>';
        var_export($e);
        echo '</small></pre>';
    }

    /**
     * @param \Models\User $user
     * @throws Exception
     */
    public static function setCurrentUser(User &$user) {
        if (!self::$current_user) {
            self::$current_user = $user;
        } else {
            throw new Exception("Double set for current user");
        }
    }

    /**
     * @return \Models\User
     */
    public static function &getCurrentUser() {
        return self::$current_user;
    }

    /**
     * @return Document
     */
    public static function getDocument() {
        return self::$document;
    }

    public static function getLang() {
        return empty(self::$lang)
            ? (empty($_SESSION['lang'])
                ? Config::instance()->lang->default
                : $_SESSION['lang'])
            : self::$lang;
    }

    public static function setLang($l) {
        $_SESSION['lang'] = $l;
        self::$lang = $l;
    }

    protected function output() {
        self::$document
            ->render($this->controller
                ->run($this->action, Path::getInstance()->tail())
                ->render())
            ->output();
    }

    public static function error($code = '000', $message = '') {
        $c = new \Controllers\Error();
        $a = "e{$code}";
        self::$document
            ->render($c
                ->run($a, array($message))
                ->render())
            ->output();
        exit;
    }

    public function setController($c) {
        $ns = NS . 'Controllers' . NS;

        $c = $ns . (ucfirst($c));

        try {
            $c = new $c;
        } catch (Exception $e) {
            App::error(404, $e->getMessage());
        }

        $this->controller = $c;

        return $this;
    }

    /**
     * @param $a
     * @return App $this
     */
    public function setAction($a) {
        $this->action = $a;
        return $this;
    }

    /**
     * @param string $url
     */
    public static function redirect($url) {
        header('Location: ' . $url);
        exit;
    }
}